package com.multiplay.tetris;

import java.util.Random;

import com.multiplay.GlobalDefs;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class PlayFieldView extends View 
{
    protected final int CUP_CONFIG_LEN = 48;
    protected final float [] cup_config = new float[CUP_CONFIG_LEN];

    protected static final int CUP_TOP_MARGIN = 56;
    protected static final int CUP_LEFT_MARGIN = 30;
    protected static final int CUP_RIGHT_MARGIN = 150;
    protected static final int CUP_LINE_WIDTH = 4;
    protected static final int MAX_ELEMENTS = 7;
    
    protected boolean [][] cup_model = null;
    protected GameBlock current_block = null;
    
    protected int current_level;
    protected int removed_lines;

    protected int w_block, h_block;
    protected Random random = null;
    
    public static final int CUP_WIDTH = 10;
    public static final int CUP_HEIGHT = 18;

    public PlayFieldView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        random = new Random();
        random.setSeed(System.currentTimeMillis());
        
        current_level = 1;
        removed_lines = 0;
        
        init_model();
    }

    @Override
    protected void onLayout (boolean changed, int left, int top, int right,
        int bottom)
    {
        super.onLayout(changed, left, top, right, bottom);

        if (changed)
            fill_lines_array();
    }

    protected void init_model()
    {
        cup_model = new boolean[CUP_WIDTH][CUP_HEIGHT];

        for (int i = 0; i < CUP_WIDTH; i++)
            for (int j = 0; j < CUP_HEIGHT; j++)
                cup_model[i][j] = false;
    }
    
    protected boolean first_check(int [] block_coord, boolean set)
    {
        boolean rc = true;
        int x, y;
        
        for (int i = 0; i < 4; i++)
        {
            x = block_coord[i * 2];
            y = block_coord[i * 2 + 1];
            
            if (cup_model[x][y])
            {
                rc = false;
                break;
            }
        }
        
        if (!rc && set)
            set_block_to_model(block_coord);
        
        return rc;
    }
    
    protected void fill_lines_array()
    {
        int w = getWidth();
        int h = getHeight();

        w_block = (w - CUP_LEFT_MARGIN - CUP_RIGHT_MARGIN) / CUP_WIDTH;
        h_block = (h - CUP_TOP_MARGIN - CUP_LINE_WIDTH) / CUP_HEIGHT;
        
        Log.v(GlobalDefs.LOG_APP_TAG, "w=" + w_block + " h=" + h_block);
        
        for (int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12] = CUP_LEFT_MARGIN - i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 1] = CUP_TOP_MARGIN;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 2] = CUP_LEFT_MARGIN - i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 3] = h - CUP_LINE_WIDTH + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 4] = CUP_LEFT_MARGIN - i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 5] = h - CUP_LINE_WIDTH + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 6] = w - CUP_RIGHT_MARGIN + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 7] = h - CUP_LINE_WIDTH + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 8] = w - CUP_RIGHT_MARGIN + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 9] = h - CUP_LINE_WIDTH + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 10] = w - CUP_RIGHT_MARGIN + i;
        for(int i = 0; i < CUP_LINE_WIDTH; i++)
            cup_config[i * 12 + 11] = CUP_TOP_MARGIN;
    }

    protected void game_over()
    {
        ((MainWindow)getContext()).stop_timer();
        Toast.makeText(getContext(), "Game over", Toast.LENGTH_SHORT).show();
    }
    
    protected void set_block_to_model(int [] block_coord)
    {
        int x, y;
        
        for (int i = 0; i < 4; i++)
        {
            x = block_coord[i * 2];
            y = block_coord[i * 2 + 1];
            
            cup_model[x][y] = true;
        }
        
        current_block = null;
    }
    
    protected boolean check_tauch(int [] block_coord)
    {
        boolean rc = false;
        int x, y;
        
        for (int i = 0; i < 4; i++)
        {
            x = block_coord[i * 2];
            y = block_coord[i * 2 + 1];
            
            if (y + 1 == CUP_HEIGHT)
            {
                rc = true;
                break;
            }
            if (cup_model[x][y + 1])
            {
                rc = true;
                break;
            }
        }
        
        if (rc)
            set_block_to_model(block_coord);
        
        return rc;
    }
    
    protected void step_down()
    {
        current_block.move_down(1);
    }

    public void rotate_block()
    {
    	if (!current_block.prepare_rotation())
    		return;
    	
    	boolean set = true;
    	int [] coord = current_block.get_rotated_block_data();
    	if (coord == null || !first_check(coord, false))
    		set = false;
    	
    	current_block.finish_rotation(set);
    	
    	if (set)
    		invalidate();
    }

    public void drop_block()
    {
        int x, y, deep, min_deep = CUP_HEIGHT;;
        
        for (int i = 0; i < 4; i++)
        {
            x = current_block.get_block_coord()[i * 2];
            y = current_block.get_block_coord()[i * 2 + 1];
            deep = 0;
            for (int j = y + 1; j < CUP_HEIGHT; j++)
            {
                if (!cup_model[x][j])
                    deep++;
                else
                    break;
            }
            if (deep < min_deep)
                min_deep = deep;
        }
        
        if (min_deep == 0)
        	return;
        
        current_block.move_down(min_deep);
        invalidate();
    }
    
    public void step_left()
    {
        int x, y;
        boolean move = true;
        
        for (int i = 0; i < 4; i++)
        {
            x = current_block.get_block_coord()[i * 2];
            y = current_block.get_block_coord()[i * 2 + 1];
            
            if (x == 0 || cup_model[x - 1][y])
            {
                move = false;
                break;
            }
        }
        if (move)
        {
            current_block.step_left();
            invalidate();
        }
    }
    
    public void step_right()
    {
        int x, y;
        boolean move = true;
        
        for (int i = 0; i < 4; i++)
        {
            x = current_block.get_block_coord()[i * 2];
            y = current_block.get_block_coord()[i * 2 + 1];
            
            if (x + 1 == CUP_WIDTH || cup_model[x + 1][y])
            {
                move = false;
                break;
            }
        }
        if (move)
        {
            current_block.step_rigth();
            invalidate();
        }
    }
    
    protected void remove_line(int line)
    {
    	removed_lines++;
    	
        if (line == 0)
        {
            for (int i = 0; i < CUP_WIDTH; i++)
                cup_model[i][0] = false;
            
            return;
        }
        int filled = 0;
        for (int y = line; y > 0; y--)
        {
            filled = 0;
            for (int x = 0; x < CUP_WIDTH; x++)
            {
                cup_model[x][y] = cup_model[x][y - 1];
                if (cup_model[x][y - 1])
                    filled++;
            }
            if (filled == 0)
                break;
        }
        if (filled != 0)
            for (int i = 0; i < CUP_WIDTH; i++)
                cup_model[i][0] = false;
    }
    
    protected boolean check_full_lines()
    {
        int full = 0;
        
        for (int y = CUP_HEIGHT - 1; y >= 0; y--)
        {
            full = 0;
            for (int x = 0; x < CUP_WIDTH; x++)
            {
                if (cup_model[x][y])
                    full++;
            }
            if (full == CUP_WIDTH)
            {
                remove_line(y);
                check_full_lines();
                break;
            }
        }
        return (full == CUP_WIDTH) ? true : false;
    }
    
    public void timer_tick()
    {
		if (current_block == null ||
			check_tauch(current_block.get_block_coord()))
		{
			current_block =
	    		GameBlock.create_block(random.nextInt(MAX_ELEMENTS));
	    	if (!first_check(current_block.get_block_coord(), true))
	    		game_over();
		}
		else
		{
			step_down();
		}
    	
        invalidate();
        if (check_full_lines())
            invalidate();
    }
    
    protected void draw_block(int x, int y, Canvas canvas, Paint fg_paint,
        Paint bg_paint)
    {
        int start_x = CUP_LEFT_MARGIN + x * w_block;
        int start_y = CUP_TOP_MARGIN + y * h_block;
        RectF r = new RectF();
        r.left = start_x;
        r.top = start_y;
        r.right = r.left + w_block;
        r.bottom = r.top + h_block;

        canvas.drawRoundRect (r, 3, 3, fg_paint);
        canvas.drawCircle(start_x + 15, start_y + 15, 3, bg_paint);
    }

    protected void draw_cup(Canvas canvas, Paint fg, Paint bg)
    {
        int start_x = CUP_LEFT_MARGIN + w_block / 2;
        int start_y = CUP_TOP_MARGIN + h_block / 2;
        
        for (int i = 0; i < CUP_WIDTH; i++)
        {
            for (int j = 0; j < CUP_HEIGHT; j++)
            {
                if (!cup_model[i][j])
                {
                    canvas.drawCircle(start_x + i * w_block,
                        start_y + j * h_block, 4, fg);
                    canvas.drawCircle(start_x + i * w_block,
                        start_y + j * h_block, 3, bg);
                }
                else
                {
                    draw_block(i, j, canvas, fg, bg);
                }
            }
        }
    }
    
    protected void draw_new_element(Canvas canvas, Paint fg, Paint bg)
    {
    	if (current_block == null)
    		return;
    	
        for (int i = 0; i < 4; i++)
        {
            draw_block(current_block.get_block_coord()[i * 2],
            	current_block.get_block_coord()[i * 2 + 1], canvas, fg, bg);
        }
    }
    
    protected void draw_text_info(Canvas canvas, Paint paint)
    {
    	float x, y;
    	float interline_spacing;
    	
    	paint.setTextSize(24);
    	interline_spacing = paint.getFontMetrics(null);
    	
    	x = getWidth() - CUP_RIGHT_MARGIN + 20;
    	y = CUP_TOP_MARGIN + 20;
    	canvas.drawText("Level: " + current_level, x, y, paint);
    	y += interline_spacing;
    	canvas.drawText("Line: " + removed_lines, x, y, paint);
    }
    
    public void draw (Canvas canvas)
    {
        Paint fg_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        fg_paint.setColor(0xFFFBFBFB);
        Paint bg_paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        bg_paint.setColor(0xFF000000);

        canvas.save();
        draw_text_info(canvas, fg_paint);
        canvas.restore();
        
        canvas.save();
        canvas.drawLines(cup_config, fg_paint);
        
        fg_paint.setColor(0xFFBBBBBB);
        draw_cup(canvas, fg_paint, bg_paint);
        
        fg_paint.setColor(0xFFFBFBFB);
        draw_new_element(canvas, fg_paint, bg_paint);
        
        canvas.restore();
    }
}
